
.global _interrupt_vector_base
.global _exit_interrupt
.global _interrupt_vector
.global _raise_sw_interrupt

_interrupt_vector:	/* Loads at SWI vector address 0xFFFF0000 */
nop				/* reset vector */
ldr pc, [pc, #36]			/* undefined instruction */
ldr pc, [pc, #28]		/* Handling for SWI. r0 contains the handler */
ldr pc, [pc, #32]			/* Prefetch abort */
ldr pc, [pc, #32]			/* data abort */
nop                                     /* reserved */
nop				/* IRQ mode. Same handling as FIQ */
nop                             /* FIQ mode */
ldr pc, [pc, #-0]
nop
/*.word 0xFFFEE084 */
.word _hw_int_handler 
.word _sw_int_handler
.word _und_exception_handler
.word _prefetch_abort_exception_handler
.word _data_abort_exception_handler

_und_exception_handler:
mov r0, #1
mov r1, lr
bl exception_handler		/* does not return */

_prefetch_abort_exception_handler:
mov r0, #2
mov r1, lr
bl exception_handler		/* does not return */

_data_abort_exception_handler:
mov r0, #3
mov r1, lr
bl exception_handler		/* does not return */

/*
* Interrupt handling
* (NESTED INTERRUPTS NOT SUPPORTED IN DESIGN)
*
* > Save registers on stack
* > Push interrupt handler address on stack
*
* --- common handling starts for SWI / IRQ / FIQ interrupts ---
* > Call the interrupt handler from the stack address
* > if preemption was from privilege mode
* >   reload stack registers
* >   movs to the saved mode
* > Else if preemption was from user mode
* >   disable further interrupts
* >   if the preempted user process is still the candidate
* >     reload stack registers and movs to user mode
* >   else if the candidate user process has changed
* >     store stacked registers in process PCB
* >     load the next candidate process
* >   endif
* > endif
*/

_pre_interrupt_handling:
/* We can use r0-r5 as they are already saved */
/* r6 needs to be preserved, r7 contains the return address */
/* Move to system mode to access
 * user mode registers
*/
mov r1, sp
mrs r2, cpsr

mrs r0, spsr
orr r4, r2, #0x1F
msr cpsr, r4

mov r3, sp /* save sp */
mov sp, r1
STMFD sp!, {r0, r14}
STMFD sp!, {r3}
STMFD sp!, {r8-r12} /* Now stack has: r0-r7, pc+4, r8-r12, sp, psr, lr */
mov sp, r3  /* restore stack pointer */
msr cpsr, r2  /* Back to interrupt mode */
sub sp, sp, #32

/* debug code 
mov r0, sp
STMFD sp!, {lr}
bl dump_stack
LDMFD sp!, {lr}
 end debug */

mov pc, r7


_hw_int_handler:

STMFD sp!, {r0-r7, lr}   /* Save minimum active registers */

/* disable interrupts */
mrs r0, cpsr
orr r0, r0, #0xC0
msr cpsr, r0


mov r7, pc
b _pre_interrupt_handling

/* debug 
mov r0, #10
bl reached
 end debug */

ldr r1, [pc, #20]
ldr r3, [r1]
ldr r2, [pc, #8]
mov pc, r2
nop
nop
.word _common_int_handler
.word 0xFFFEE084

_sw_int_handler:
add lr, lr, #4           /* later we shall be executing pc = lr - 4 */
STMFD sp!, {r0-r7, lr}

/* disable interrupts */
mrs r1, cpsr
orr r1, r1, #0xC0
msr cpsr, r1

mov r6, r0       /* r0 contains data corresponding to the interrupt */
mov r7, pc
b _pre_interrupt_handling

ldr r0, [lr, #-8]  /* fetch instruction executed: swi x */
mov r1, #0xFF
bic r0, r0, r1, LSL #24  /* r0 = interrupt number */

mov r1, r6		/* data corresponding to interrupt */
ldr r3, [pc, #16]
ldr r2, [pc, #8]
mov pc, r2
nop
nop
.word _common_int_handler
.word sw_interrupt_handler

_common_int_handler:
/* 
 * r3: contains the address of the handler
 * r0: contains the argument 1 for the handler
 * r1: contains the argument 2 for the handler
*/
blx r3  /* call the interrupt handler, r0 and r1 are arguments */

/* debug 
mov r0, #1
bl reached
 end debug */

_exit_interrupt:

/* debug 
mov r0, #2
bl reached
 end debug */

mov r0, sp  /* pointer to saved registers */
bl scheduler

cmp r0, #0
beq _resume_current_user_process /* preempted process remains the active process */

/* Old registers are saved, now switch to new user mode candidate */
add sp, sp, #68   /* unwind stack, registers already stored in PCB */

/* r0 contains the process registers */

/* move to system mode to access user mode registers */

/*
* The addresses were stored in stack in following fashion:
* stmfd r0-r7,lr
* stmfd r8-r12,sp,psr,lr
* Need to be retrieved in the same order
*/
mrs r2, cpsr
orr r3,r2,#0x1F
msr cpsr, r3

ldr r8, [r0,#0]
ldr r9, [r0,#4]
ldr r10, [r0,#8]
ldr r11, [r0,#12]
ldr r12, [r0,#16]
ldr sp, [r0,#20]
ldr lr, [r0,#28]

/* move back to privilege mode */
msr cpsr, r2

ldr r1, [r0,#24]
msr spsr, r1

ldr r1, [r0,#36]
ldr r2, [r0,#40]
ldr r3, [r0,#44]
ldr r4, [r0,#48]
ldr r5, [r0,#52]
ldr r6, [r0,#56]
ldr r7, [r0,#60]
ldr lr, [r0,#64]

ldr r0, [r0,#32]
subs pc, lr, #4   

_resume_current_user_process:
/* debug 
mov r0 , sp
bl dump_stack 
 end debug */

LDMFD sp!, {r8-r12}
add sp, sp, #12  /* unwind stack to skip sp, psr, lr */
LDMFD sp!, {r0-r7, lr}
subs pc, lr, #4

__dummy_interrupt_handler:
mov pc, lr	/* just return */

_interrupt_vector_base:
BL __dummy_interrupt_handler	/* 00 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 01 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 02 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 03 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 04 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 05 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 06 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 07 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 08 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 09 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 10 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 11 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 12 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 13 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 14 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 15 */
B _exit_interrupt
BL sdcard_interrupt_handler	/* 16 */
B _exit_interrupt
BL sdcard_interrupt_handler	/* 17 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 18 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 19 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 20 */
B _exit_interrupt
BL user_timer_interrupt_handler	/* 21 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 22 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 23 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 24 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 25 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 26 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 27 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 28 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 29 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 30 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 31 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 32 */
B _exit_interrupt
BL emac_c0_rx_thres		/* 33 */
B _exit_interrupt
BL emac_c0_rx			/* 34 */
B _exit_interrupt
BL emac_c0_tx			/* 35 */
B _exit_interrupt
BL emac_c0_misc			/* 36 */
B _exit_interrupt
BL emac_c1_rx_thres		/* 37 */
B _exit_interrupt
BL emac_c1_rx			/* 38 */
B _exit_interrupt
BL emac_c1_tx			/* 39 */
B _exit_interrupt
BL emac_c1_misc			/* 40 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 41 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 42 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 43 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 44 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 45 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 46 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 47 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 48 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 49 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 50 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 51 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 52 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 53 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 54 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 55 */
B _exit_interrupt
BL spi1_interrupt_handler	/* 56 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 57 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 58 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 59 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 60 */
B _exit_interrupt
BL uart_interrupt_handler	/* 61 */
B _exit_interrupt 
BL __dummy_interrupt_handler	/* 62 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 63 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 64 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 65 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 66 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 67 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 68 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 69 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 70 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 71 */
B _exit_interrupt
BL sdcard_interrupt_handler	/* 72 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 73 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 74 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 75 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 76 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 77 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 78 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 79 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 80 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 81 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 82 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 83 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 84 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 85 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 86 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 87 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 88 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 89 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 90 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 91 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 92 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 93 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 94 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 95 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 96 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 97 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 98 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 99 */
B _exit_interrupt
BL __dummy_interrupt_handler	/* 100 */
B _exit_interrupt

.end
